//滑雪

//方法一：bfs

#include<iostream>
#include<queue>
#include <algorithm>
using namespace std;
#define maxn 104
 
int dx[]={1,-1,0,0};
int dy[] = {0,0,1,-1};
int answer[maxn][maxn],a[maxn][maxn];
int answermax=0;
int m,n;



int dfs(int x,int y ){
    int flag=0;
    for (int i=0;i<4;i++){
    	int xx= dx[i]+x;
    	int yy = dy[i]+y;
    	if(xx>0&&xx<=n&&yy>0&&yy<=m && a[xx][yy]<a[x][y]) {//
    		flag=1;
    		//cout<<xx<<" " <<yy<<endl; 
    		if (answer[xx][yy]) {
    			answer[x][y]=max(1+answer[xx][yy],answer[x][y]);
    			
    		}
    		else answer[x][y] = max(dfs(xx,yy)+1,answer[x][y]);	
       } 	
    }
    
    if (flag==0){
    	answer[x][y]=1;return 1;
    	
    } 
    return answer[x][y];
   
}
int main(){
	cin>>n>>m;
	for (int i=1;i<=n;i++){
		for (int j=1;j<=m;j++){
			cin>>a[i][j];
		}
	}
	
    for (int i=1;i<=n;i++){
		for (int j=1;j<=m;j++){
			int k = dfs(i,j);
			answermax =max(answermax,k);
			
	    }
	}
	cout<<answermax;
	
} 




//方法二： dfs
#include<iostream>
using namespace std;
#define MAX 103
int a[MAX][MAX];
int vis[MAX][MAX];
int times=1;
int num[MAX];
int ans=0;
int max2=0,max1=0,n; 
int dir[][2]={0,1,1,0,0,-1,-1,0};
	int R,C;
void dfs(int x,int y){
		int i;
	int flag=0;
	for(i=0;i<4;i++){
		int dx=dir[i][0];
		int dy=dir[i][1];
	
		
		if(!(x+dx<0||x+dx>=R||y+dy<0||y+dy>=C)&&a[x+dx][y+dy]<a[x][y]){
			if(vis[x+dx][y+dy]!=0){
			int k=times+vis[x+dx][y+dy];
			if(k>max1){
				max1=k;	
			}
			continue;
		}
			flag=1;
			times++;
			dfs(x+dir[i][0],y+dir[i][1]);
			times--;
			//flag=0;
		}
	}
		if(flag==0){
			if(max1<times){
				max1=times;
			}
		}
	return ;
}



int main(){
	int i,j;
	cin>>R>>C;
	for(i=0;i<R;i++){
		for(j=0;j<C;j++){
			cin>>a[i][j];
			vis[i][j]=0;
			
		}
	}
	/*for(i=0;i<R;i++){
		for(j=0;j<C;j++){
			if(a[i][j]>max1)//又可以剪枝 
			{
				times++;
				dfs(i,j);
			}
			
		}
	}
for(i=0;i<R;i++){
		for(j=0;j<C;j++){
		if(a[i][j]>=max2){
				dfs(i,j);
			vis[i][j]=max1;
			
			if(max1>max2){
				max2=max1;
			}
			max1=0;
		}
		
		}
	}
	cout<<max2;
}*/



//填涂颜色：
#include <bits\stdc++.h>
using namespace std;
//1.理清思路，先干什么在干什么
//2.全局变量的初始化与定义
//3.函数的编写，主1函数的应用
//4.z注意输入输出格式 
#define maxn 1000

//转化成：闭合圈染色问题 
struct node {
	int xx,yy;
};
int a[maxn][maxn],flag[maxn][maxn]; 
queue<node> q;
int dx[]={1,-1,0,0};
int dy[] = {0,0,1,-1};
int n ;

int bfs(){//对周围染色 
	
   	while (!q.empty()){
   		
   		node qq = q.front();
   		q.pop();
   		//cout<<qq.xx<< qq.yy<<endl;
   		for (int i =0;i<4;i++){
   			int x = qq.xx+dx[i];
   			int y = qq.yy+dy[i];
   			if (flag[x][y]==0&&a[x][y]==0){//周围复制成-1 
   				flag[x][y] =1;//指的是访问过得 
   				q.push(node {x,y});//
			   }
		   }
	   }
	
}

int main(){
    cin>>n;
    
	for (int i =0;i<=n+1;i++){
		
		for (int j =0;j<=n+1;j++){
			if(i==0 || j==0||i==n+1||j==n+1){
				a[i][j]=-1;
			}
			else {
				cin>>a[i][j];
				flag[i][j]=0;
			}
		}
	}
	
	for (int i=1;i<=n;i++){
		for (int j=1;j<=n;j++){
			if (i==1||j==1||i==n||j==n) {
				if (a[i][j]==0 )flag[i][j]=1, q.push(node {i,j}),bfs();
			}
		}
	}
	
	for (int i=1;i<=n;i++){
		for (int j=1;j<=n;j++){
			if(a[i][j]==0&&flag[i][j]==0){
				cout <<2<<" ";
			}
			else cout<<a[i][j]<<" ";
			
		}
		cout<<endl;
	}
}
//方法二： 
#include <bits/stdc++.h>
using namespace std;
int a[32][32],b[32][32];
int dx[5]={0,-1,1,0,0};
int dy[5]={0,0,0,-1,1};//第一个表示不动，是充数的，后面的四个分别是上下左右四个方向
int n,i,j;
void dfs(int p,int q){
    int i;
    if (p<0||p>n+1||q<0||q>n+1||a[p][q]!=0) return;//如果搜过头或者已经被搜过了或者本来就是墙的就往回
    a[p][q]=1;//染色
    for (i=1;i<=4;i++) dfs(p+dx[i],q+dy[i]);//向四个方向搜索
}
int main(){
    cin>>n;
    for (i=1;i<=n;i++)
        for (j=1;j<=n;j++){
            cin>>b[i][j];//其实不拿两个数组也可以，不过我喜欢啦
            if (b[i][j]==0) a[i][j]=0;
            else a[i][j]=2;
        }
    dfs(0,0);//搜索 从0，0开始搜
    for (i=1;i<=n;i++){
        for (j=1;j<=n;j++)
        if (a[i][j]==0) cout<<2<<' ';//如果染过色以后i，j那个地方还是0，说明没有搜到，就是周围有墙，当然就是被围住了，然后输出2
        else cout<<b[i][j]<<' ';//因为被染色了，本来没有被围住的水和墙都染成了1，所以就输出b[i][j]
        cout<<'\n';//换行
    }
}